﻿
namespace Budgetsch.Web.Services
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Data;
    using System.Linq;
    using System.ServiceModel.DomainServices.EntityFramework;
    using System.ServiceModel.DomainServices.Hosting;
    using System.ServiceModel.DomainServices.Server;
    using Budgetsch.Web.EntityModel;
    using System.Web;

    public class SerializableResult
    {
        public string Result { get; set; }
    }
    // Implements application logic using the BudgetschEntities context.
    // TODO: Add your application logic to these methods or in additional methods.
    // TODO: Wire up authentication (Windows/ASP.NET Forms) and uncomment the following to disable anonymous access
    // Also consider adding roles to restrict access as appropriate.
    //[RequiresAuthentication]
    [EnableClientAccess()]
    public class BudgetschDomainService : LinqToEntitiesDomainService<BudgetschEntities>
    {

        [Invoke]
        public byte[] GetExcelData()
        {
            //TODO execute excel generating
            return ExcelGenerator.GenerateExcel(GetIncomesForMonth(11));
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'Costs' query.
        [Query(IsDefault = true)]
        public IQueryable<Cost> GetCosts()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.Costs.Where(i => i.User.ID == user.ID);
        }

        public IEnumerable<Cost> GetCostsForMonth(int month_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var costs = this.ObjectContext.Costs.Where(i => i.User.ID == user.ID).ToList();
            return costs.Where(i => i.StartDate.Month == month_ && i.StartDate.Year == DateTime.Now.Year && !i.IsRecurring || i.IsRecurring && GeneratedOccurences(i.StartDate, i.Delta.Value, i.EndDate.Value).Any(o => o.Year == DateTime.Now.Year && o.Month == month_));
        }

        public IEnumerable<Cost> GetCostsForYear(int year_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var costs = this.ObjectContext.Costs.Where(i => i.User.ID == user.ID).ToList();
            return costs.Where(i => i.StartDate.Year == year_ && !i.IsRecurring || i.IsRecurring && GeneratedOccurences(i.StartDate, i.Delta.Value, i.EndDate.Value).Any(o => o.Year == year_));
        }

        public void InsertCost(Cost cost)
        {
            if ((cost.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(cost, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                cost.User = user;
                this.ObjectContext.Costs.AddObject(cost);
            }
        }

        public void UpdateCost(Cost currentCost)
        {
            this.ObjectContext.Costs.AttachAsModified(currentCost, this.ChangeSet.GetOriginal(currentCost));
        }

        public void DeleteCost(Cost cost)
        {
            if ((cost.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(cost, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.Costs.Attach(cost);
                this.ObjectContext.Costs.DeleteObject(cost);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'CostCategories' query.
        [Query(IsDefault = true)]
        public IQueryable<CostCategory> GetCostCategories()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.CostCategories.Where(ic => ic.User.ID == user.ID);
        }

        public IQueryable<CostCategory> GetCostCategoriesWithItems()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var x = this.ObjectContext.CostCategories.Include("Costs").Where(ic => ic.User.ID == user.ID);
            return x;
        }

        public void InsertCostCategory(CostCategory costCategory)
        {
            if ((costCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(costCategory, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                costCategory.User = user;
                this.ObjectContext.CostCategories.AddObject(costCategory);
            }
        }

        public void UpdateCostCategory(CostCategory currentCostCategory)
        {
            this.ObjectContext.CostCategories.AttachAsModified(currentCostCategory, this.ChangeSet.GetOriginal(currentCostCategory));
        }

        public void DeleteCostCategory(CostCategory costCategory)
        {
            if ((costCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(costCategory, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.CostCategories.Attach(costCategory);
                this.ObjectContext.CostCategories.DeleteObject(costCategory);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'CostComments' query.
        [Query(IsDefault = true)]
        public IQueryable<CostComment> GetCostComments()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var userCosts = this.ObjectContext.Costs.Where(i => i.UserID == user.ID);
            var comments = this.ObjectContext.CostComments.Include("User").Include("Cost.CostCategory").Where(ic => userCosts.Select(ui => ui.ID).Contains(ic.CostID));
            return comments;
        }

        public void InsertCostComment(CostComment costComment)
        {
            if ((costComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(costComment, EntityState.Added);
            }
            else
            {
                this.ObjectContext.CostComments.AddObject(costComment);
            }
        }

        public void UpdateCostComment(CostComment currentCostComment)
        {
            this.ObjectContext.CostComments.AttachAsModified(currentCostComment, this.ChangeSet.GetOriginal(currentCostComment));
        }

        public void DeleteCostComment(CostComment costComment)
        {
            if ((costComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(costComment, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.CostComments.Attach(costComment);
                this.ObjectContext.CostComments.DeleteObject(costComment);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'Currencies' query.
        [Query(IsDefault = true)]
        public IQueryable<Currency> GetCurrencies()
        {
            return this.ObjectContext.Currencies;
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'Incomes' query.
        [Query(IsDefault = true)]
        public IQueryable<Income> GetIncomes()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.Incomes.Where(i => i.User.ID == user.ID);
        }

        public IEnumerable<Income> GetIncomesForMonth(int month_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var incomes = this.ObjectContext.Incomes.Where(i => i.User.ID == user.ID).ToList();
            return incomes.Where(i => i.StartDate.Month == month_ && i.StartDate.Year == DateTime.Now.Year && !i.IsRecurring || i.IsRecurring && GeneratedOccurences(i.StartDate, i.Delta.Value, i.EndDate.Value).Any(o => o.Year == DateTime.Now.Year && o.Month == month_));
        }

        public IEnumerable<Income> GetIncomesForYear(int year_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var incomes = this.ObjectContext.Incomes.Where(i => i.User.ID == user.ID).ToList();
            return incomes.Where(i => i.StartDate.Year == year_ && !i.IsRecurring || i.IsRecurring && GeneratedOccurences(i.StartDate, i.Delta.Value, i.EndDate.Value).Any(o => o.Year == year_));
        }

        private IEnumerable<DateTime> GeneratedOccurences(DateTime start_, int delta_, DateTime end_)
        {
            var date = start_;
            do
            {
                yield return date;
                date = date + new TimeSpan(7 * delta_, 0, 0, 0);
            } while (date <= end_);
        }

        public void InsertIncome(Income income)
        {
            if ((income.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(income, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                income.User = user;
                this.ObjectContext.Incomes.AddObject(income);
            }
        }

        public void UpdateIncome(Income currentIncome)
        {
            this.ObjectContext.Incomes.AttachAsModified(currentIncome, this.ChangeSet.GetOriginal(currentIncome));
        }

        public void DeleteIncome(Income income)
        {
            if ((income.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(income, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.Incomes.Attach(income);
                this.ObjectContext.Incomes.DeleteObject(income);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'IncomeCategories' query.
        [Query(IsDefault = true)]
        public IQueryable<IncomeCategory> GetIncomeCategories()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.IncomeCategories.Where(ic => ic.User.ID == user.ID);
        }

        public IQueryable<IncomeCategory> GetIncomeCategoriesWithItems()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var x = this.ObjectContext.IncomeCategories.Include("Incomes").Where(ic => ic.User.ID == user.ID);
            return x;
        }

        public void InsertIncomeCategory(IncomeCategory incomeCategory)
        {
            if ((incomeCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(incomeCategory, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                incomeCategory.User = user;
                this.ObjectContext.IncomeCategories.AddObject(incomeCategory);
            }
        }

        public void UpdateIncomeCategory(IncomeCategory currentIncomeCategory)
        {
            this.ObjectContext.IncomeCategories.AttachAsModified(currentIncomeCategory, this.ChangeSet.GetOriginal(currentIncomeCategory));
        }

        public void DeleteIncomeCategory(IncomeCategory incomeCategory)
        {
            if ((incomeCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(incomeCategory, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.IncomeCategories.Attach(incomeCategory);
                this.ObjectContext.IncomeCategories.DeleteObject(incomeCategory);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'IncomeComments' query.
        [Query(IsDefault = true)]
        public IQueryable<IncomeComment> GetIncomeComments()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var userIncomes = this.ObjectContext.Incomes.Where(i => i.UserID == user.ID);
            var comments = this.ObjectContext.IncomeComments.Include("User").Include("Income.IncomeCategory").Where(ic => userIncomes.Select(ui => ui.ID).Contains(ic.IncomeID));
            return comments;

        }

        public void InsertIncomeComment(IncomeComment incomeComment)
        {
            if ((incomeComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(incomeComment, EntityState.Added);
            }
            else
            {
                this.ObjectContext.IncomeComments.AddObject(incomeComment);
            }
        }

        public void UpdateIncomeComment(IncomeComment currentIncomeComment)
        {
            this.ObjectContext.IncomeComments.AttachAsModified(currentIncomeComment, this.ChangeSet.GetOriginal(currentIncomeComment));
        }

        public void DeleteIncomeComment(IncomeComment incomeComment)
        {
            if ((incomeComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(incomeComment, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.IncomeComments.Attach(incomeComment);
                this.ObjectContext.IncomeComments.DeleteObject(incomeComment);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'Savings' query.
        [Query(IsDefault = true)]
        public IQueryable<Saving> GetSavings()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.Savings.Where(i => i.User.ID == user.ID); ;
        }

        public IEnumerable<Saving> GetSavingsForMonth(int month_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var savings = this.ObjectContext.Savings.Where(i => i.User.ID == user.ID).ToList();
            return savings.Where(i => i.Date.Month == month_ && i.Date.Year == DateTime.Now.Year);
        }

        public IEnumerable<Saving> GetSavingsForYear(int year_)
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var savings = this.ObjectContext.Savings.Where(i => i.User.ID == user.ID).ToList();
            return savings.Where(i => i.Date.Year == year_);
        }

        public void InsertSaving(Saving saving)
        {
            if ((saving.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(saving, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                saving.User = user;
                this.ObjectContext.Savings.AddObject(saving);
            }
        }

        public void UpdateSaving(Saving currentSaving)
        {
            this.ObjectContext.Savings.AttachAsModified(currentSaving, this.ChangeSet.GetOriginal(currentSaving));
        }

        public void DeleteSaving(Saving saving)
        {
            if ((saving.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(saving, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.Savings.Attach(saving);
                this.ObjectContext.Savings.DeleteObject(saving);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'SavingCategories' query.
        [Query(IsDefault = true)]
        public IQueryable<SavingCategory> GetSavingCategories()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            return this.ObjectContext.SavingCategories.Where(ic => ic.User.ID == user.ID);
        }

        public IQueryable<SavingCategory> GetSavingCategoriesWithItems()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var x = this.ObjectContext.SavingCategories.Include("Savings").Where(ic => ic.User.ID == user.ID);
            return x;
        }

        public void InsertSavingCategory(SavingCategory savingCategory)
        {
            if ((savingCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(savingCategory, EntityState.Added);
            }
            else
            {
                var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
                savingCategory.User = user;
                this.ObjectContext.SavingCategories.AddObject(savingCategory);
            }
        }

        public void UpdateSavingCategory(SavingCategory currentSavingCategory)
        {
            this.ObjectContext.SavingCategories.AttachAsModified(currentSavingCategory, this.ChangeSet.GetOriginal(currentSavingCategory));
        }

        public void DeleteSavingCategory(SavingCategory savingCategory)
        {
            if ((savingCategory.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(savingCategory, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.SavingCategories.Attach(savingCategory);
                this.ObjectContext.SavingCategories.DeleteObject(savingCategory);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'SavingComments' query.
        [Query(IsDefault = true)]
        public IQueryable<SavingComment> GetSavingComments()
        {
            var user = this.ObjectContext.Users.SingleOrDefault(u => u.UserName == HttpContext.Current.User.Identity.Name);
            var userSavings = this.ObjectContext.Savings.Where(i => i.UserID == user.ID);
            var comments = this.ObjectContext.SavingComments.Include("User").Include("Saving.SavingCategory").Where(ic => userSavings.Select(ui => ui.ID).Contains(ic.SavingID));
            return comments;
        }

        public void InsertSavingComment(SavingComment savingComment)
        {
            if ((savingComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(savingComment, EntityState.Added);
            }
            else
            {
                this.ObjectContext.SavingComments.AddObject(savingComment);
            }
        }

        public void UpdateSavingComment(SavingComment currentSavingComment)
        {
            this.ObjectContext.SavingComments.AttachAsModified(currentSavingComment, this.ChangeSet.GetOriginal(currentSavingComment));
        }

        public void DeleteSavingComment(SavingComment savingComment)
        {
            if ((savingComment.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(savingComment, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.SavingComments.Attach(savingComment);
                this.ObjectContext.SavingComments.DeleteObject(savingComment);
            }
        }

        // TODO:
        // Consider constraining the results of your query method.  If you need additional input you can
        // add parameters to this method or create additional query methods with different names.
        // To support paging you will need to add ordering to the 'Users' query.
        [Query(IsDefault = true)]
        public IQueryable<User> GetUsers()
        {
            return this.ObjectContext.Users;
        }

        public User GetCurrentUser()
        {
            return this.ObjectContext.Users.Where(u => u.UserName == HttpContext.Current.User.Identity.Name).SingleOrDefault();
        }

        public void InsertUser(User user)
        {
            if ((user.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(user, EntityState.Added);
            }
            else
            {
                this.ObjectContext.Users.AddObject(user);
            }
        }

        public void UpdateUser(User currentUser)
        {
            this.ObjectContext.Users.AttachAsModified(currentUser, this.ChangeSet.GetOriginal(currentUser));
        }

        public void DeleteUser(User user)
        {
            if ((user.EntityState != EntityState.Detached))
            {
                this.ObjectContext.ObjectStateManager.ChangeObjectState(user, EntityState.Deleted);
            }
            else
            {
                this.ObjectContext.Users.Attach(user);
                this.ObjectContext.Users.DeleteObject(user);
            }
        }
    }
}


